package org.spiderflow.selenium.io;

import com.gargoylesoftware.htmlunit.javascript.host.performance.PerformanceEntry;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.core.har.HarEntry;
import org.apache.commons.exec.util.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.xerces.xs.datatypes.ObjectList;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spiderflow.annotation.Comment;
import org.spiderflow.annotation.Example;
import org.spiderflow.io.SpiderResponse;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

public class SeleniumResponse implements SpiderResponse{
	private static final Logger logger = LoggerFactory.getLogger(SeleniumResponse.class);

	private final WebDriver driver;

	private Actions actionsObj;

	public SeleniumResponse(WebDriver driver){
		this.driver = driver;
	}

	@Override
	public int getStatusCode() {
		return 0;
	}

	@Override
	public String getTitle() {
		return driver.getTitle();
	}

	@Override
	public byte[] getBytes() {
		return null;
	}

	@Override
	public String getHtml() {
		return driver.getPageSource();
	}

	@Override
	public Map<String, String> getCookies() {
		Set<Cookie> cookies = driver.manage().getCookies();
		Map<String,String> cookieMap = new HashMap<>();
		if(cookies != null){
			for (Cookie cookie : cookies) {
				cookieMap.put(cookie.getName(), cookie.getValue());
			}
		}
		return cookieMap;
	}

	@Override
	public Map<String, String> getHeaders() {
		return null;
	}

	@Override
	public String getContentType() {
		return null;
	}

	@Override
	public String getUrl() {
		return driver.getCurrentUrl();
	}

	public WebDriver getDriver() {
		return driver;
	}

	public SeleniumResponse switchTo(int index){
		driver.switchTo().frame(index);
		return this;
	}
	public SeleniumResponse switchTo(String name){
		driver.switchTo().frame(name);
		return this;
	}
	public SeleniumResponse switchTo(WebElement element){
		driver.switchTo().frame(element);
		return this;
	}

	public SeleniumResponse switchToDefault(){
		driver.switchTo().defaultContent();
		return this;
	}

	public void quit(){
		try {
			driver.quit();
		} catch (Exception ignored) {
		}
	}

	public Actions action(){
		if(actionsObj == null){
			this.actionsObj = new Actions(this.driver);
		}
		return this.actionsObj;
	}

	public void clearAction(){
		this.actionsObj = null;
	}

	@Comment("获取网络日志")
	@Example("获取所有请求日志：${resp.networks()}")
	public Object networks(){
		// 默认取最近5条日志
		return networks(-5,null);
	}

	@Comment("获取网络日志")
	@Example("获取最近10条请求日志：${resp.networks(-10)}")
	public Object networks(int limit){
		return networks(limit,null);
	}

	@Comment("获取网络日志")
	@Example("获取最近10条mp3请求日志：${resp.networks(-10, '^(?i).*\\.mp3$')}")
	public Object networks(int limit, String regex){
		List<Map<String,Object>> list = new ArrayList<>();
		String scriptToExecute = "var performance = " +
				"window.performance || " +
				"window.mozPerformance || " +
				"window.msPerformance || " +
				"window.webkitPerformance || {}; " +
				"var network = performance.getEntries() || {}; " +
				"return network;";
		Object netData = ((JavascriptExecutor)driver).executeScript(scriptToExecute);

		try{
			if(netData instanceof ArrayList<?>){
				List<?> tempList = (ArrayList<?>)netData;
				if(!tempList.isEmpty()){
					if(limit < 0) {
						Collections.reverse(tempList);
						limit = limit * -1;
					}
					int total = tempList.size();
					boolean hasUrlRegex = StringUtils.isNotBlank(regex);
					boolean hasLimit = limit>0 && total > limit;
					int count = 0;
					for (Object o : tempList){
						if(o instanceof Map<?,?>){
							Map<?,?> tempMap = (Map<?,?>)o;
							Map<String,Object> item = new HashMap<>();
							Object name = tempMap.get("name");
							String url = name == null ? "" : name.toString();
							if(url.isEmpty()){
								continue;
							}
							if(hasUrlRegex && !url.matches(regex)){
								continue;
							}
							item.put("url", url);
							list.add(item);
							count++;
							if(hasLimit && count >= limit){
								break;
							}
						}
					}
				}
			}
		}catch (Exception e){
			logger.error("解析网络日志异常{}",e.getMessage());
		}

		return list;
	}
}
